package net.neptech.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import net.neptech.bo.MenuBo;
import net.neptech.mapper.MenuMapper;
import net.neptech.mapper.RoleMapper;
import net.neptech.mapper.RoleMenuMapper;
import net.neptech.model.sys.Menu;
import net.neptech.model.sys.Role;
import net.neptech.model.sys.RoleMenu;
import net.neptech.service.MenuService;
import net.neptech.utils.BeanCopyUtils;
import net.neptech.utils.MapstructUtils;
import net.neptech.utils.SecurityUtils;
import cn.hutool.core.util.IdUtil;
import net.neptech.utils.StreamUtils;
import net.neptech.utils.StringUtils;
import net.neptech.vm.constant.UserConstants;
import net.neptech.vo.MenuVo;
import net.neptech.vo.MetaVo;
import net.neptech.vo.RouterVo;
import net.neptech.vo.TreeSelectVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author: liyuxiang
 * @Date: 2025/8/13 18:30
 * @Description: TODO
 */
@Service
public class MenuServiceImpl implements MenuService {
    @Autowired
    MenuMapper menuMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    RoleMenuMapper roleMenuMapper;

    /**
     * 根据用户ID查询菜单
     *
     * @param userId 用户名称
     * @return 菜单列表
     */
    @Override
    public List<Menu> selectMenuTreeByUserId(Long userId) {
        List<Menu> menus;
        if (SecurityUtils.isAdmin(userId)) {
            menus = menuMapper.selectMenuTreeAll();
        } else {
            menus = menuMapper.selectMenuTreeByUserId(userId);
        }
        return getChildPerms(menus, 0);
    }

    @Override
    public List<RouterVo> buildMenus(List<Menu> menus) {
        List<RouterVo> routers = new LinkedList<>();
        for (Menu menu : menus) {
            RouterVo router = new RouterVo();
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(menu.getRouteName());
            router.setPath(menu.getRouterPath());
            router.setComponent(menu.getComponentInfo());
            router.setQuery(menu.getQueryParam());
            router.setMenuType(menu.getMenuType());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache().toString()), menu.getPath()));
            List<Menu> cMenus = menu.getChildren();
            if (CollUtil.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            } else if (menu.isMenuFrame()) {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponentInfo());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache().toString()), menu.getPath()));
                children.setQuery(menu.getQueryParam());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == 0 && menu.isInnerLink()) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                String routerPath = Menu.innerLinkReplaceEach(menu.getPath());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    @Override
    public List<MenuVo> selectMenuList(MenuBo menuBo, Long userId) {
        List<MenuVo> menuList;
        // 管理员显示所有菜单信息
        if (SecurityUtils.isAdmin(userId)) {
            menuList = menuMapper.selectVoList(new LambdaQueryWrapper<Menu>()
                    .like(StringUtils.isNotBlank(menuBo.getMenuName()), Menu::getMenuName, menuBo.getMenuName())
                    .eq(StringUtils.isNotNull(menuBo.getVisible()), Menu::getVisible, menuBo.getVisible())
                    .eq(StringUtils.isNotNull(menuBo.getStatus()), Menu::getStatus, menuBo.getStatus())
                    .orderByAsc(Menu::getParentId)
                    .orderByAsc(Menu::getOrderNum), MenuVo.class);
        } else {
            QueryWrapper<Menu> wrapper = Wrappers.query();
            wrapper.eq("u.user_id", userId)
                   .eq("sm.status", 0)
                   .eq("r.status", "0")
                   .eq("s.staff_status", "1")
                   .like(StringUtils.isNotBlank(menuBo.getMenuName()), "sm.menu_name", menuBo.getMenuName())
                   .eq(StringUtils.isNotNull(menuBo.getVisible()), "sm.visible", menuBo.getVisible())
                   .eq(StringUtils.isNotNull(menuBo.getStatus()), "sm.status", menuBo.getStatus())
                   .orderByAsc("sm.parent_id")
                   .orderByAsc("sm.order_num");
            List<Menu> list = menuMapper.selectMenuListByUserId(wrapper);
            menuList = BeanCopyUtils.copyBeanList(list, MenuVo.class);
        }
        return menuList;
    }

    @Override
    public List<Menu> selectMenuList(Long userId) {
        return BeanCopyUtils.copyBeanList(selectMenuList(new MenuBo(), userId), Menu.class);
    }

    @Override
    public Set<String> selectMenuPermsByUserId(Long userId) {
        List<String> perms = menuMapper.selectMenuPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;

    }

    @Override
    public void updateMenu(MenuBo menuBo) {
        Menu menu = BeanCopyUtils.copyBean(menuBo, Menu.class);

        // 处理菜单类型转换
        if (menuBo.getMenuType() != null) {
            if ("M".equals(menuBo.getMenuType().toString())) {
                menu.setMenuType(0); // 目录
            } else if ("C".equals(menuBo.getMenuType().toString())) {
                menu.setMenuType(1); // 菜单
            } else if ("F".equals(menuBo.getMenuType().toString())) {
                menu.setMenuType(2); // 按钮
            }
        }

        if (menu.getMenuId() != null) {
            menuMapper.updateById(menu);
        } else {
            // 新增时设置默认值 - 使用简单的ID生成
            Long maxId = menuMapper.selectList(null).stream()
                                   .mapToLong(Menu::getMenuId)
                                   .max()
                                   .orElse(0L);
            menu.setMenuId(maxId + 1);
            menuMapper.insert(menu);
        }
    }

    @Override
    public MenuVo selectMenuById(Long menuId) {
        Menu menu = menuMapper.selectById(menuId);
        return BeanCopyUtils.copyBean(menu, MenuVo.class);
    }

    @Override
    public List<TreeSelectVo> buildMenuTreeSelect(List<MenuVo> menus) {
        List<TreeSelectVo> treeSelectList = new ArrayList<>();

        // 找出所有根节点（父节点ID为0或不存在父节点的）
        List<MenuVo> rootMenus = StreamUtils.filter(menus, menu -> menu.getParentId() == null || menu.getParentId() == 0);

        for (MenuVo rootMenu : rootMenus) {
            TreeSelectVo treeSelect = buildTreeSelectNode(rootMenu, menus);
            treeSelectList.add(treeSelect);
        }

        return treeSelectList;
    }

    @Override
    public void deleteMenuById(Long menuId) {
        menuMapper.deleteById(menuId);
    }

    @Override
    public List<Long> selectMenuListByRoleId(Long roleId) {
        Role role = roleMapper.selectById(roleId);
        return menuMapper.selectMenuListByRoleId(roleId);
    }

    private TreeSelectVo buildTreeSelectNode(MenuVo menu, List<MenuVo> allMenus) {
        TreeSelectVo treeSelect = new TreeSelectVo();
        treeSelect.setId(menu.getMenuId());
        treeSelect.setLabel(menu.getMenuName());
        treeSelect.setDisabled(false);

        // 查找当前菜单的子菜单
        List<MenuVo> children = StreamUtils.filter(allMenus, child -> menu.getMenuId().equals(child.getParentId()));

        if (CollUtil.isNotEmpty(children)) {
            List<TreeSelectVo> childTreeSelects = new ArrayList<>();
            for (MenuVo child : children) {
                childTreeSelects.add(buildTreeSelectNode(child, allMenus));
            }
            treeSelect.setChildren(childTreeSelects);
        }

        return treeSelect;
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    private List<Menu> getChildPerms(List<Menu> list, int parentId) {
        List<Menu> returnList = new ArrayList<>();
        for (Menu t : list) {
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<Menu> list, Menu t) {
        // 得到子节点列表
        List<Menu> childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId()));
        t.setChildren(childList);
        for (Menu tChild : childList) {
            // 判断是否有子节点
            if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) {
                recursionFn(list, tChild);
            }
        }
    }
}
